Wagging the Dog: Abusing Resource-Based Constrained Delegation to Attack Active Directory
Back in March 2018, I embarked on an arguably pointless crusade to prove that the TrustedToAuthForDelegation attribute was meaningless, and that “protocol transition” can be achieved without it. I believed that security wise, once constrained delegation was enabled (msDS-AllowedToDelegateTo was not null), it did not matter whether it was configured to use “Kerberos only” or “any authentication protocol”.
I started the journey with Benjamin Delpy’s (@gentilkiwi) help modifying Kekeo to support a certain attack that involved invoking S4U2Proxy with a silver ticket without a PAC, and we had partial success, but the final TGS turned out to be unusable. Ever since then, I kept coming back to it, trying to solve the problem with different approaches but did not have much success. Until I finally accepted defeat, and ironically then the solution came up, along with several other interesting abuse cases and new attack techniques.
TL;DR
This post is lengthy, and I am conscious that many of you do not have the time or attention span to read it, so I will try to convey the important points first:
- Resource-based constrained delegation does not require a forwardable TGS when invoking S4U2Proxy.
- S4U2Self works on any account that has an SPN, regardless of the state of the TrustedToAuthForDelegation attribute. If TrustedToAuthForDelegation is set, then the TGS that S4U2Self produces is forwardable, unless the principal is sensitive for delegation or a member of the Protected Users group.
- The above points mean that if an attacker can control a computer object in Active Directory, then it may be possible to abuse it to compromise the host.
- S4U2Proxy always produces a forwardable TGS, even if the provided additional TGS in the request was not forwardable.
- The above point means that if an attacker compromises any account with an SPN as well as an account with classic constrained delegation, then it does not matter whether the TrustedToAuthForDelegation attribute is set.
- By default, any domain user can abuse the MachineAccountQuota to create a computer account and set an SPN for it, which makes it even more trivial to abuse resource-based constrained delegation to mimic protocol transition (obtain a forwardable TGS for arbitrary users to a compromised service).
- S4U2Self allows generating a valid TGS for arbitrary users, including those marked as sensitive for delegation or members of the Protected Users group. The resulting TGS has a PAC with a valid KDC signature. All that’s required is the computer account credentials or a TGT.
- The above point in conjunction with unconstrained delegation and “the printer bug” can lead to remote code execution (RCE).
- Resource-based constrained delegation on the krbtgt account allows producing TGTs for arbitrary users, and can be abused as a persistence technique.
- Configuring resource-based constrained delegation through NTLM relay from HTTP to LDAP may facilitate remote code execution (RCE) or local privilege escalation (LPE) on MSSQL servers, and local privilege escalation (LPE) on Windows 10/2016/2019.
- Computer accounts just got a lot more interesting. Start hunting for more primitives to trigger attack chains!
Kerberos Delegation 101
If you are not up to speed with abusing Kerberos delegation, you should first read the post S4U2Pwnage by Will Schroeder (@harmj0y) and Lee Christensen (@tifkin_). In that post, they explained it better than I ever could, but I will try to capture it very concisely as well.
First, a simplified overview of Kerberos:
- When users log in, they encrypt a piece of information (a timestamp) with an encryption key derived from their password, to prove to the authentication server that they know the password. This step is called “preauthentication”.
- In Active Directory environments, the authentication server is a domain controller.
- Upon successful preauthentication, the authentication server provides the user with a ticket-granting-ticket (TGT), which is valid for a limited time.
- When a user wishes to authenticate to a certain service, the user presents the TGT to the authentication server. If the TGT is valid, the user receives a ticket-granting service (TGS), also known as a “service ticket”, from the authentication server.
- The user can then present the TGS to the service they want to access, and the service can authenticate the user and make authorisation decisions based on the data contained in the TGS.
A few important notes about Kerberos tickets:
- Every ticket has a clear-text part and an encrypted part.
- The clear-text part of the ticket contains the Service Principal Name (SPN) of the service for which the ticket is intended.
- The encryption key used for the encrypted part of the ticket is derived from the password of the account of the target service.
- TGTs are encrypted for the built-in account “krbtgt”.
- The SPN on TGTs is krbtgt/domain name.
Often, there is a requirement for a service to impersonate the user to access another service. To facilitate that, the following delegation features were introduced to the Kerberos protocol:
- Unconstrained Delegation (TrustedForDelegation): The user sends a TGS to access the service, along with their TGT, and then the service can use the user’s TGT to request a TGS for the user to any other service and impersonate the user.
- Constrained Delegation (S4U2Proxy): The user sends a TGS to access the service (“Service A”), and if the service is allowed to delegate to another pre-defined service (“Service B”), then Service A can present to the authentication service the TGS that the user provided and obtain a TGS for the user to Service B. Note that the TGS provided in the S4U2Proxy request must have the FORWARDABLE flag set. The FORWARDABLE flag is never set for accounts that are configured as “sensitive for delegation” (the USER_NOT_DELEGATED attribute is set to true) or for members of the Protected Users group.
- Protocol Transition (S4U2Self/TrustedToAuthForDelegation): S4U2Proxy requires the service to present a TGS for the user to itself before the authentication service produces a TGS for the user to another service. It is often referred to as the “additional ticket”, but I like referring to it as “evidence” that the user has indeed authenticated to the service invoking S4U2Proxy. However, sometimes users authenticate to services via other protocols, such as NTLM or even form-based authentication, and so they do not send a TGS to the service. In such cases, a service can invoke S4U2Self to ask the authentication service to produce a TGS for arbitrary users to itself, which can then be used as “evidence” when invoking S4U2Proxy. This feature allows impersonating users out of thin air, and it is only possible when the TrustedToAuthForDelegation flag is set for the service account that invokes S4U2Self.
The Other Constrained Delegation
Back in October 2018, I collaborated with Will Schroeder (@harmj0y) to abuse resource-based constrained delegation as an ACL-based computer object takeover primitive. Will wrote an excellent post on this topic, which you should also read before continuing. Once again, in that post, Will explained it better than I ever could, but I will try to capture it very concisely here.
In order to configure constrained delegation, one has to have the SeEnableDelegation Privilege, which is sensitive and typically only granted to Domain Admins. In order to give users/resources more independence, Resource-based Constrained Delegation was introduced in Windows Server 2012. Resource-based constrained delegation allows resources to configure which accounts are trusted to delegate to them.
This flavour of constrained delegation is very similar to the classic constrained delegation but works in the opposite direction. Classic constrained delegation from account A to account B is configured on account A in the msDS-AllowedToDelegateTo attribute, and defines an “outgoing” trust from A to B, while resource-based constrained delegation is configured on account B in the msDS-AllowedToActOnBehalfOfOtherIdentity attribute, and defines an “incoming” trust from A to B.
An important observation is that every resource can configure resource-based constrained delegation for itself. In my mind, it does make sense to allow resources to decide for themselves who do they trust.
Will and I came up with the following abuse case to compromise a specific host:
- An attacker compromises an account that has the TrustedToAuthForDelegation flag set (“Service A”).
- The attacker additionally compromises an account with the rights to configure resource-based constrained delegation for the computer account of the target host (“Service B”).
- The attacker configures resource-based constrained delegation from Service A to Service B.
- The attacker invokes S4U2Self and S4U2Proxy as Service A to obtain a TGS for a privileged user to Service B to compromise the target host.
The following diagram illustrates this abuse case:
It is a nice trick, but compromising an account with the TrustedToAuthForDelegation flag set is not trivial. If only my crusade to defeat TrustedToAuthForDelegation had been more fruitful, it would come in handy for this abuse case.
A Selfless Abuse Case: Skipping S4U2Self
In an attempt to make the above ACL-based computer object takeover primitive more generic, I slightly modified Rubeus to allow skipping S4U2Self by letting the attacker supply the “evidence” TGS for the victim when invoking S4U2Proxy. Benjamin Delpy also made this modification to Kekeo back in April 2018; however, at the time of writing, Kekeo does not support resource-based constrained delegation.
The more generic abuse case would work as follows:
- The attacker compromises Service A and the DACL to configure resource-based constrained delegation on Service B.
- By way of social engineering or a watering hole attack, the victim authenticates to Service A to access a service (e.g. CIFS or HTTP).
- The attacker dumps the TGS of the victim to Service A, using Mimikatz sekurlsa::tickets or through another method.
- The attacker configures resource-based constrained delegation from Service A to Service B.
- The attacker uses Rubeus to perform S4U2Proxy with the TGS previously obtained as the required “evidence”, from Service A to Service B for the victim.
- The attacker can pass-the-ticket and impersonate the victim to access Service B.
The following diagram illustrates this scenario:
Video demonstration of this scenario:
Note that the resulting TGS in the S4U2Proxy response (to service B) seems to have the FORWARDABLE flag set, unless the principal is marked as sensitive for delegation or is a member of the Protected Users group.
Serendipity
As I was testing my Rubeus modification in preparation for submitting a pull request, I reset the TrustedToAuthForDelegation UserAccountControl flag on Service A and expected to see an error message when performing S4U2Self. However, S4U2Self worked, as well as S4U2Proxy, and the resulting TGS provided me with access to Service B.
The ticket I obtained from S4U2Self was not forwardable, and still, S4U2Proxy accepted it and responded with a TGS for the user to Service B.
At this point, I was wondering whether I completely misconfigured my lab environment.
Video demonstration of this scenario:
A Misunderstood Feature #1
After a couple more hours of testing, debugging, and reading MS-SFU, I realised that I had misunderstood S4U2Self. It seems S4U2Self works whether the TrustedToAuthForDelegation UserAccountControl flag is set or not. However, if it is not set, the resulting TGS is not FORWARDABLE, as per section 3.2.5.1.2 of MS-SFU:
“If the TrustedToAuthenticationForDelegation parameter on the Service 1 principal is set to:
A Misunderstood Feature #2
So, S4U2Proxy still shouldn’t have worked with a non-forwardable ticket, right?
When I attempted invoking S4U2Proxy with a non-forwardable TGS with classic (“outgoing”) constrained delegation, it failed. But with resource-based constrained delegation (“incoming”) it consistently worked. I thought it must be a bug, and so on 26/10/2018, I reported it to Microsoft Response Center (MSRC).
As I was impatiently waiting for a response, I read MS-SFU again and found section 3.2.5.2:
“If the service ticket in the additional-tickets field is not set to forwardable<20> and the PA-PAC-OPTIONS [167] ([MS-KILE] section 2.2.10) padata type has the resource-based constrained delegation bit:
It seems like a design flaw, also known in Microsoft parlance as a “feature”. S4U2Proxy for resource-based constrained delegation works when provided with a non-forwardable TGS by design!
Note that as per the above documentation, even though the TGS doesn’t have to be forwardable for resource-based constrained delegation, if the user is set as “sensitive for delegation”, S4U2Proxy will fail, which is expected.
Generic DACL Abuse
These two misunderstood “features” mean that the only requirement for the ACL-based computer object takeover primitive is the DACL to configure resource-based constrained delegation on the computer object and another account. Any account with an SPN will do. Even just a TGT for the other account will be enough.
The reason an SPN is required is that S4U2Self does not seem to work for accounts that do not have it. But any domain user can obtain an account with an SPN by abusing the MachineAccountQuota, which is set to 10 by default, and allows creating new computer accounts. When creating the new computer account, the user can set an SPN for it, or add one later on. Kevin Robertson (@NetSPI) implemented a tool called Powermad that allows doing that through LDAP.
The generic abuse case would work as follows:
- The attacker compromises an account that has an SPN or creates one (“Service A”) and the DACL to configure resource-based constrained delegation on a computer account (“Service B”).
- The attacker configures resource-based constrained delegation from Service A to Service B.
- The attacker uses Rubeus to perform a full S4U attack (S4U2Self and S4U2Proxy) from Service A to Service B for a user with privileged access to Service B.
- The attacker can pass-the-ticket and impersonate the user to gain access to Service B.
The following diagram illustrates this scenario:
Video demonstration of this scenario:
Note that the TGS obtained from S4U2Self in step 3 is not forwardable, and yet it is accepted as “evidence” when invoking S4U2Proxy.
A Forwardable Result
When I inspected the resulting TGS in the S4U2Proxy response, it had the FORWARDABLE flag set. I provided S4U2Proxy with a non-forwardable TGS as “evidence” and got a forwardable TGS.
Is this a bug or a feature?
I went back to MS-SFU section 3.2.5.2.2, and found the following:
“The KDC MUST reply with the service ticket where:
- The sname field contains the name of Service 2.
- The realm field contains the realm of Service 2.
- The cname field contains the cname from the service ticket in the additional-tickets field.
- The crealm field contains the crealm from the service ticket in the additional-tickets field.
- The FORWARDABLE ticket flag is set.
- The S4U_DELEGATION_INFO structure is in the new PAC.”
It seems like it is another great feature: every TGS produced by S4U2Proxy is always forwardable.
Empowering Active Directory Objects and Reflective Resource-Based Constrained Delegation
When Microsoft introduced resource-based constrained delegation, it transformed users and computers into strong, independent AD objects, which are able to configure this new “incoming” delegation for themselves. By default, all resources have an Access Control Entry (ACE) that permits them to configure resource-based constrained delegation for themselves. However, if an attacker has credentials for the account, they can forge a silver ticket and gain access to it anyway.
The problem with silver tickets is that, when forged, they do not have a PAC with a valid KDC signature. If the target host is configured to validate KDC PAC Signature, the silver ticket will not work. There may also be other security solutions that can detect silver ticket usage.
However, if we have credentials for a computer account or even just a TGT, we can configure resource-based constrained delegation from that account to itself, and then use S4U2Self and S4U2Proxy to obtain a TGS for an arbitrary user.
The abuse case would work as follows:
- The attacker compromises credentials or a TGT for a computer account (“Service A”).
- The attacker configures resource-based constrained delegation from Service A to itself.
- The attacker uses Rubeus to perform a full S4U attack and obtain a TGS for a user with privileged access to Service A.
- The attacker can pass-the-ticket and impersonate the user to access Service A.
The following diagram illustrates this scenario:
Video demonstration of this scenario:
This reflective resource-based constrained delegation is, in fact, equivalent to S4U2Self when the account has the TrustedToAuthForDelegation flag set (also known as “protocol transition”), as it allows the account to obtain a forwardable TGS for itself on behalf of users. However, if an account is configured for classic constrained delegation with “Kerberos only” (TrustedToAuthForDelegation is not set and msDS-AllowedToDelegateTo is not null), then the classic conditions take precedence over the resource-based conditions, and so S4U2Self responds with a non-forwardable TGS and S4U2Proxy fails.
Note that this technique will only allow obtaining a TGS for a user as long as it is not set as “sensitive for delegation” and is not a member of the Protected Users group, as you can see in the screenshots below:
Solving a Sensitive Problem
Inspecting the above output closely indicates that S4U2Self works for a user marked as sensitive for delegation and a member of the Protected Users group.
Closer inspection of the ticket shows that it does not have a valid service name, and it is not forwardable:
But this can easily be changed because the service name is not in the encrypted part of the ticket.
An attacker can use an ASN.1 editor to modify the SPN on the TGS obtained from S4U2Self, and turn it into a valid one.
Once that is done, the attacker has a valid TGS. It is not forwardable, but it is fine for authenticating to the service:
Video demonstration of this scenario:
So, if an attacker has credentials or a TGT for a computer account, they can obtain a TGS to that computer for any user, including sensitive/protected users, with a valid KDC signature in the PAC.
That means that obtaining a TGT for a computer account is sufficient to compromise the host.
When the Stars Align: Unconstrained Delegation Leads to RCE
As Lee Christensen (@tifkin_) demonstrated in “the printer bug” abuse case study at DerbyCon 8, it is possible to trick the Printer Spooler to connect back over SMB to a specified IP/hostname, by invoking the method RpcRemoteFindFirstPrinterChangeNotification (Opnum 62).
If an attacker compromises a host with unconstrained delegation, “the printer bug” abuse can result in remote code execution on any domain-joined Windows host with the Printer Spooler running.
The abuse case would work as follows:
- The attacker compromises a host with unconstrained delegation and elevates.
- The attacker runs the monitor/harvest module of Rubeus.
- The attacker launches SpoolSample or dementor.py to manipulate the Printer Spooler of the target host to delegate its TGT to the unconstrained delegation compromised host.
- The attacker can use the captured TGT to obtain a TGS to the target host for any user, even sensitive for delegation/protected users.
- The attacker obtains a TGS to the target host for a user with local administrator rights and compromises it.
The following diagram illustrates this scenario:
Video demonstration of this scenario:
As Will Schroeder (@harmj0y) explained in his blog post Not A Security Boundary: Breaking Forest Trusts, unconstrained delegation works across forest boundaries, making this attack effective across bidirectional forest trusts.
When Accounts Collude - TrustedToAuthForDelegation Who?
For years, Active Directory security experts have been telling us that if we must configure Kerberos delegation, constrained delegation is the way to go, and that we should use “Kerberos only” rather than “any authentication protocol” (as known as “protocol transition”). But perhaps the choice between “Kerberos only” and “Any authentication protocol” does not actually matter.
We now know that we can abuse resource-based constrained delegation to get a forwardable TGS for arbitrary users. It follows that if we have credentials (or a TGT) for an account with an SPN and for an account with classic constrained delegation but without “protocol transition”, we can combine these two “features” to mimic “protocol transition”.
This abuse case would work as follows:
- The attacker compromises an account that has an SPN or creates one (“Service A”).
- The attacker compromises an account (“Service B”), which is set for classic constrained delegation to a certain service class at Service C with Kerberos only (TrustedToAuthForDelegation is not set on Service B, and msDS-AllowedToDelegateTo on Service B contains a service on Service C, such as “time/Service C”).
- The attacker sets resource-based constrained delegation from Service A to Service B (setting msDS-AllowedToActOnBehalfOfOtherIdentity on Service B to contain “Service A” using Service B credentials or a TGT for Service B).
- The attacker uses Service A credentials/TGT to perform a full S4U2 attack and obtains a forwardable TGS for the victim to Service B.
- The attacker uses Service B credentials/TGT to invoke S4U2Proxy with the forwardable TGS from the previous step, and obtains a TGS for the victim to time/Service C. The attacker can modify the service class of the resulting TGS, for example from “time” to “cifs”, because the service name is not protected.
- The attacker can pass-the-ticket to gain access to Service C.
The following diagram illustrates this scenario:
Video demonstration of this scenario:
Unconstrained Domain Persistence
Once attackers compromise the domain, they can obviously configure resource-based constrained delegation on strategic objects, such as domain controllers, and obtain a TGS on-demand. But resource-based constrained delegation can also be configured to generate TGTs on-demand as a domain persistence technique.
Once the domain is compromised, resource-based constrained delegation can be configured from a compromised account to the krbtgt account to produce TGTs.
The abuse case would work as follows:
- The attacker compromises the domain and an account that has an SPN or creates one (“Service A”).
- The attacker configures resource-based constrained delegation from Service A to krbtgt.
- The attacker uses Rubeus to perform a full S4U attack and obtain a TGS for an arbitrary user to krbtgt, which is, in fact, a TGT.
- The attacker can use the TGT to request a TGS to arbitrary services.
The following diagram illustrates this scenario:
Video demonstration of this scenario:
In this scenario, the account Service A obtained a degree of power somewhat similar to that of the KDC in the sense that it can produce a TGT for arbitrary users.
Arguably, more subtle persistence can be achieved through a new access control entry (ACE) to allow configuring resource-based constrained delegation on-demand, rather than leaving it in plain sight.
Thinking Outisde the Box: RCE/LPE Opportunities
As shown above, if an attacker can compromise a host with unconstrained delegation, RCE can be achieved with “the printer bug” and S4U2Self. But unconstrained delegation is not a trivial condition, so I attempted to come up with an attack chain that does not require unconstrained delegation.
As mentioned above, every resource has the rights to configure resource-based constrained delegation for itself, which can be done via LDAP. This primitive opens the door to RCE/LPE opportunities if an attacker is in a position to perform a successful NTLM relay of a computer account authentication to LDAP.
The abuse case would work as follows:
- The attacker compromises an account that has an SPN or creates one (“Service A”).
- The attacker triggers a computer account authentication using a primitive such as “the printer bug”.
- The attacker performs an NTLM relay of the computer account (“Service B”) authentication to LDAP on the domain controller.
- The attacker configures resource-based constrained delegation from Service A to Service B.
- The attacker uses Rubeus to perform a full S4U attack and obtain a TGS to Service B for a user that has local administrator rights on that host.
- The attacker can pass-the-ticket and gain RCE/LPE, depending on the primitive used to trigger the computer account authentication.
The above scenario is straightforward and too good to be true. However, the reality is that NTLM relay is more complicated than it seems.
NTLM Relay 101
NetNTLM is a challenge-response authentication protocol designed by Microsoft for Windows environments. In the NetNTLM protocol, three messages are exchanged:
- The client sends a NEGOTIATE message to request authentication and “advertise capabilities”.
- The server sends a CHALLENGE message that contains a random 8-byte nonce.
- The client sends an AUTHENTICATE message that contains a response to the challenge. The response is calculated using a cryptographic function with a key derived from the user’s password (the NTLM hash).
The server validates the response to the challenge. If it is valid, authentication is successful. Otherwise, authentication fails.
The protocol is susceptible to the following relay attack:
- An attacker in a man-in-the-middle position waits for an incoming NEGOTIATE message from a victim.
- The attacker relays the NEGOTIATE message to the target server.
- The target server sends a CHALLENGE message to the attacker.
- The attacker relays the CHALLENGE message to the victim.
- The victim generates a valid AUTHENTICATE message and sends it to the attacker.
- The attacker relays the valid AUTHENTICATE message to the target server.
- The target server accepts the AUTHENTICATE message and the attacker is authenticated successfully.
The following diagram illustrates an NTLM relay attack:
The NetNTLM protocol does not only provide authentication but can also facilitate a session key exchange for encryption (“sealing”) and signing. The client and the server negotiate whether sealing/signing is required through certain flags in the exchanged messages. The exchanged session key is RC4 encrypted using a key derived from the client’s NTLM hash. The client obviously holds the NTLM hash and can decrypt it. However, a domain member server does not hold the NTLM hash of domain users, but only of local users. When a domain user exchanges a session key with a member server, the member server uses the Netlogon RPC protocol to validate the client’s response to the challenge with a domain controller, and if a session key was exchanged then the key to decrypt it is calculated by the domain controller and provided to the member server. This separation of knowledge ensures that the member server does not obtain the NTLM hash of the client, and the domain controller does not obtain the session key.
If the client and server negotiate a session key for signing, an attacker performing a relay attack can successfully authenticate, but will not be able to obtain the session key to sign subsequent messages, unless the attacker can obtain one of the following:
- The NTLM hash of the victim.
- Credentials for the computer account of the target server.
- Compromise a domain controller.
However, if the attacker obtains any of the above, they do not need to perform an NTLM relay attack to compromise the target host or impersonate the victim, and this is the reason signing mitigates NTLM relay attacks.
NTLM Relay 201
The goal is to perform a successful relay, without negotiating signing or encryption, from any protocol to LDAP.
Most of the primitives I am aware of for eliciting a connection from a computer account are initiated by the SMB client or the RPC client, both of which always seem to negotiate signing. If signing was negotiated in the NTLM exchange, the LDAP service on domain controllers ignores all unsigned messages (tested on Windows Server 2016 and Windows Server 2012R2).
The most obvious next move is to reset the flags that negotiate signing during the NTLM relay. However, Microsoft introduced a MIC (Message Integrity Code, I believe) to the NTLM protocol to prevent that. The MIC is sent by the client in the AUTHENTICATE message, and it protects the integrity of all three NTLM messages using HMAC-MD5 with the session key. If a single bit of the NTLM messages had been altered, the MIC would be invalid and authentication would fail.
Not all clients support MIC, such as Windows XP/2003 and prior, and so it is not mandatory. So another thing to try would be omitting the MIC during the NTLM relay. However, there is a flag that indicates whether a MIC is present or not, and that flag is part of the “salt” used when calculating the NetNTLM response to the challenge. Therefore, if the MIC is removed and the corresponding flag is reset, then the NetNTLM response will be invalid and authentication will fail.
Reflective NTLM Relay is Dead
Traditionally, NTLM relay of computer accounts was performed reflectively, meaning from a certain host back to itself. Until MS08-068, it was commonly performed to achieve RCE by relaying from SMB to SMB.
After it was patched, reflective cross-protocol NTLM relay was still possible, and was most commonly abused to achieve LPE in attacks such as Hot Potato. Cross-protocol reflective relay was patched in MS16-075, which killed reflective relays for good (or until James Forshaw brings it back). Rotten Potato/Juicy Potato is still alive and kicking, but it is a different flavour of reflective relay as it abuses local authentication, which ignores the challenge-response.
Post MS16-075 many security researchers stopped hunting for primitives that elicit computer account authentication, because without reflection they were no longer valuable.
Viable NTLM Relay Primitives for RCE/LPE
An RCE/LPE primitive would require one of the following:
- A client that does not negotiate signing, such as the web client on all Windows versions, including WebDAV clients.
- A client that does not support MIC in NTLM messages, such as Windows XP/2003 and prior.
- An LDAP service that does not ignore unsigned messages or does not verify the MIC on a domain controller that supports resource-based constrained delegation. I don’t believe that this unicorn exists.
There are different primitives for triggering the computer account to authenticate over HTTP. Some of them were abused in Hot Potato. I chose to explore those that take an arbitrary UNC path and then trigger a WebDAV client connection.
Note that on Windows servers, the WebDAV client is not installed by default. On Windows Server 2012R2 and prior, the Desktop Experience feature is required, and on Windows Server 2016 or later, the WebDAV Redirector feature is required. However, on desktops, the WebDAV client is installed by default.
As I mentioned above, it seems that some researchers no longer care for such primitives. However, as Lee Christensen (@tifkin_) demonstrated with the combination of “the printer bug” and unconstrained delegation, and as I will demonstrate below, these primitives are still exploitable, and I encourage everyone to keep hunting for them (and tell me all about it when you find them).
Getting Intranet-Zoned
By default, the web client will only authenticate automatically to hosts in the intranet zone, which means that no dots can be present in the hostname. If the relay server already has a suitable DNS record, then this is not an issue. However, if the relay server is “rogue”, an IP address will not cut it. To overcome that, ADIDNS can be abused to add a new DNS record for the relay server, as Kevin Robertson (@NetSPI) explained in his blog post Exploiting Active Directory-Integrated DNS.
Case Study 1: MSSQL RCE/LPE
MSSQL has an undocumented stored procedure called xp_dirtree that lists the file and folders of a provided path. By default, this stored procedure is accessible to all authenticated users (“Public”).
Under the following conditions, an attacker can achieve RCE/LPE (depending mainly on connectivity) by abusing the xp_dirtree stored procedure:
- The the attacker has compromised a user permitted to invoke the xp_dirtree stored procedure.
- The MSSQL service is running as Network Service, Local System, or a Virtual Account (default).
- The WebDAV client is installed and running on the target host.
The abuse case would work as follows:
- The attacker compromises credentials or a TGT for an account that has an SPN or creates one (“Service A”), and an account premitted to connect and invoke xp_dirtree on the target MSSQL instance.
- If required, the attacker uses Service A to add a DNS record using ADIDNS.
- The attacker logs in to the MSSQL service on the target host (“Service B”) and invokes xp_dirtree to trigger a connection to a rogue WebDAV NTLM relay server.
- The attacker relays the computer account NTLM authentication to the LDAP service on the domain controller, and configures resource-based constrained delegation from Service A to Service B.
- The attacker uses Rubeus to perform a full S4U attack to obtain a TGS to Service B for a user that has local administrator privileges on the target host.
- The attacker can pass-the-ticket to compromise the target host.
The following diagram illustrates this scenario:
Video demonstration of this scenario:
Matt Bush (@3xocyte) implemented “Bad Sequel” as a PoC exploit for this scenario.
Case Study 2: Windows 10/2016/2019 LPE
One late night, Matt Bush (@3xocyte), Danyal Drew (@danyaldrew) and I brainstormed ideas where to find suitable RCE/LPE primitives, and decided to explore what happens when a user changes the account picture in Windows 10/2016/2019. We analysed it with Process Monitor and quickly found that during the account picture change SYSTEM opens the picture file to read its attributes. It is a small and meaningless operation; not an arbitrary file write/read/delete. But we are humble people, and that is all we wanted.
The abuse case would work as follows:
- The attacker compromises credentials or a TGT for an account that has an SPN or creates one (“Service A”).
- The attacker gains unprivileged access to another computer running Windows 10 or Windows Server 2016/2019 with the WebDAV Redirector feature installed (“Service B”).
- If required, the attacker uses Service A to add a DNS record using ADIDNS.
- The attacker changes the account profile picture to a path on a rogue WebDAV NTLM relay server.
- The attacker relays the computer account NTLM authentication to the LDAP service on the domain controller, and configures resource-based constrained delegation from Service A to Service B.
- The attacker uses Rubeus to perform a full S4U attack to obtain a TGS to Service B for a user that has local administrator privileges on it.
- The attacker can pass-the-ticket to compromise Service B.
The following diagram illustrates this scenario:
Video demonstration of this scenario:
Mitigating Factors
Accounts marked as sensitive for delegation or members of the Protected Users group are not affected by the attacks presented here, except for the S4U2Self abuse. However, computer accounts are affected, and in my experience they are never marked as sensitive for delegation or added to the Protected Users group. I did not thoroughly test the effects of setting computer accounts as sensitive for delegation or adding them to the Protected Users group, so I cannot recommend doing that, but I do recommend exploring it.
As Lee Christensen (@tifkin_) demonstrated in “the printer bug” abuse case study at DerbyCon 8, obtaining a TGT/TGS for a domain controller allows performing “dcsync” and compromising the domain. As demonstrated above, with resource-based constrained delegation, obtaining a TGT for any computer account allows impersonating users to it and potentially compromising the host. Therefore, it is important not to configure any host for unconstrained delegation, because it can facilitate the compromise of other hosts within the forest and within other forests with bidirectional trust.
LDAP signing with channel binding can mitigate the RCE and LPE attack chains described in the case studies above.
The RCE/LPE attack chains that involve NTLM relay to LDAP abuse a default ACE that permits Self to write msDS-AllowedToActOnBehalfOfOtherIdentity. Adding a new ACE that denies Self from writing to the attribute msDS-AllowedToActOnBehalfOfOtherIdentity will interrupt these attack chains, which will then have to fall back to abusing that primitive in conjunction with unconstrained delegation. If your organisation does not use resource-based constrained delegation, you can consider adding an ACE that blocks Everyone from writing to the attribute msDS-AllowedToActOnBehalfOfOtherIdentity.
Detection
The following events can be used in the implementation of detection logic for the attacks describes in this post:
- S4U2Self: S4U2Self can be detected in a Kerberos service ticket request event (Event ID 4769), where the Account Information and Service Information sections point to the same account.
- S4U2Proxy: S4U2Proxy can be detected in a Kerberos service ticket request event (Event ID 4769), where the Transited Services attribute in the Additional Information is not blank.
- Unconstrained Domain Persistence: The domain persistence technique described above can be detected in a in a Kerberos service ticket request event (Event ID 4769), where the Transited Services attribute in the Additional Information is not blank (indicating S4U2Proxy), and the Service Information points to the “krbtgt” account.
- msDS-AllowedToActOnBehalfOfOtherIdentity: If an appropriate SACL is defined, then resource-based constrained delegation configuration changes can be detected in directory service object modification events (Event ID 5136), where the LDAP Display Name is “msDS-AllowedToActOnBehalfOfOtherIdentity”. Events where the subject identity and the object identity are the same may be an indicator for some of the attacks presented above.
A Word of Advice from Microsoft
Microsoft did highlight the risk of S4U2Proxy in section 5.1 of MS-SFU:
“The S4U2proxy extension allows a service to obtain a service ticket to a second service on behalf of a user. When combined with S4U2self, this allows the first service to impersonate any user principal while accessing the second service. This gives any service allowed access to the S4U2proxy extension a degree of power similar to that of the KDC itself. This implies that each of the services allowed to invoke this extension have to be protected nearly as strongly as the KDC and the services are limited to those that the implementer knows to have correct behavior.”
S4U2Proxy is a dangerous extension that should be restricted as much as possible. However, the introduction of resource-based constrained delegation allows any account to permit arbitrary accounts to invoke S4U2Proxy, by configuring “incoming” delegation to itself. So should we protect all accounts as strongly as the KDC?
Author
Elad Shamir (@elad_shamir)
Acknowledgements
- Will Schroeder (@harmj0y), Lee Christensen (@tifkin_), Matt Bush (@3xocyte), and Danyal Drew (@danyaldrew) for bouncing off ideas and helping me figure this out.
- Will Schroeder (@harmj0y) for Rubeus.
- Matt Bush (@3xocyte) for dementor.py, helping implement the WebDAV NTLM relay server, and implementing Bad Sequel.
- Lee Christensen (@tifkin_) for discovering “the printer bug” and implementing SpoolSample.
- Benjamin Delpy (@gentilkiwi) for modifying Kekeo and Mimikatz to support this research. And OJ Reeves (@TheColonial) for the introduction.
- Kevin Robertson (@NetSPI) for Powermad.
- Microsoft for always coming up with great ideas, and never disappointing.
Disclosure Timeline
- 26/10/2018 - Sent initial report to MSRC.
- 27/10/2018 - MSRC Case 48231 was opened and a case manager was assigned.
- 01/11/2018 - Sent an email to MSRC to let them know this behaviour actually conforms with the specification, but I believe it is still a security issue.
- 09/11/2018 - Sent an email to MSRC requesting an update on this case.
- 14/11/2018 - MSRC responded that they are still trying to replicate the issue.
- 27/11/2018 - Sent an email to MSRC providing a 60-day notice to public disclosure.
- 09/12/2018 - Send a reminder email to MSRC.
- 11/12/2018 - MSRC responded that a new case manager was assigned and the following conclusion was reached:
“The engineering team has determined this is not an issue which will be addressed via a security update but rather we need to update our documentation to highlight service configuration best practices and using a number of features such as group managed service accounts, resource based constrained delegation, dynamic access control, authentication policies, and ensuring unconstrained delegation is not enabled. The team is actively working on the documentation right now with the goal of having it published prior to your disclosure date.”
- 28/01/2019 - Public disclosure
I would like to note that my first experience with MSRC was very disappointing. The lack of dialogue was discouraging and not at all what I had expected.
This post was also published on shenaniganslabs.io.